package com.lock.redisLocks.jedix;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.lock.redisLocks.RedisHelper.ProviderConfigType;
import com.lock.redisLocks.RedisHelper.RedisConfigType;

import io.lettuce.core.RedisException;
import redis.clients.jedis.Jedis;

public class JedixWrapping {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static <E extends Jedix, T> E wrap(T tt, RedisConfigType redisConfigType, ProviderConfigType providerConfigType) {

		JedisOnCloseInvocationHandler<T> handler = new JedisOnCloseInvocationHandler<T>(tt, redisConfigType, providerConfigType);
		Class[] interfaces = null;
		{
			Class<?>[] implementedInterfaces = tt.getClass().getInterfaces();
			interfaces = new Class[implementedInterfaces.length + 1];
			interfaces[0] = Jedix.class;
			System.arraycopy(implementedInterfaces, 0, interfaces, 1, implementedInterfaces.length);
		}
		E proxiedObj = (E) Proxy.newProxyInstance(tt.getClass().getClassLoader(), interfaces, handler);

		return proxiedObj;
	}

	public static class JedisOnCloseInvocationHandler<T> implements InvocationHandler {
		// 代理类中的真实对象
		private RedisConfigType redisConfigType;
		private ProviderConfigType providerConfigType;
		private T originalObj;
		// private T proxiedObj;

		// 构造函数，给我们的真实对象赋值
		public JedisOnCloseInvocationHandler(T originalObj, RedisConfigType redisConfigType, ProviderConfigType providerConfigType) {
			this.redisConfigType = redisConfigType;
			this.providerConfigType = providerConfigType;
			this.originalObj = originalObj;
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			if (originalObj == null) {
				throw new RedisException("Connection is deallocated and cannot be used anymore.");
			}

			if (method.getName().equals("getOriginImpl")) {
				return originalObj;
			}

			if (method.getName().equals("getRedisConfigType")) {
				return redisConfigType;
			}

			if (method.getName().equals("getProviderConfigType")) {
				return providerConfigType;
			}

			if (method.getName().equals("close")) {
				if (RedisConfigType.SINGLE.equals(redisConfigType)) {
					Jedis jedis = (Jedis) originalObj;
					jedis.close();
					originalObj = null;
					return null;
				} else if (RedisConfigType.CLUSTER.equals(redisConfigType)) {
					originalObj = null;
					return null;
				} else {
					return null;
				}
			}

			// log.trace("MethodName:{}, DeclaringClass:{}", method.getName(), method.getDeclaringClass());
			Class<?>[] cArg = null;
			if (args != null) {
				// log.trace("arg.length:{}", args.length);
				cArg = new Class[args.length];
				int idx = 0;
				for (Object arg : args) {
					cArg[idx++] = arg.getClass();

					arg.getClass().getInterfaces();
					// log.trace("idx:{}, arg:{}, isArray:{}, clazzName:{}", idx++, arg, arg.getClass().isArray(), arg.getClass().getName());
				}
			}

			Method _method = originalObj.getClass().getMethod(method.getName(), cArg);
			Object invoke = _method.invoke(originalObj, args);
			//
			// Object invoke = method.invoke(originalObj, args);
			return invoke;

		}

	}

	/**
	 * 报错：
	 * object is not an instance of declaring class
	 * 说明Class没有实例化；
	 * 解决办法：
	 * 由于没有实力化可以有如下两种方法：
	 * 1、反射方法定义成为static的，故被反射类就不需要实例化；
	 * 2、method.invoke(_class.newInstance(), args);
	 */
}
